<?php

require_once("finefs/class.FineFS.php");
require_once("finefs/utils/except.ApplicationException.php");
require_once("finefs/utils/except.IOException.php");
require_once("class.FineDBCollection.php");

/**
 * Object for the management of FineDB's document.
 *
 * @author	Amaury Bouchard <amaury.bouchard@finemedia.fr>
 * @copyright	Copyright (c) 2010, FineMedia
 * @package	FineDB
 * @subpackage	lib
 * @version	$Id: class.FineDBDocument.php 8 2011-09-26 10:38:52Z amaury.bouchard $
 */
class FineDBDocument {
	/** Unique identifier of this document. */
	private $_id = null;
	/** Current collection's management object. */
	private $_collection = null;
	/** Document's data. */
	private $_data = null;
	/** Document's metadata. */
	private $_meta = null;
	/** Current state of this document: modified (and waiting to be saved) or not. */
	private $_modified = false;
	/** List of modified metadata. */
	private $_modifiedMeta = null;

	/* **************** CONSTRUCTION METHODS ******************* */
	/**
	 * Constructor.
	 * @param	FineDBCollection	$collection	Current collection's management object.
	 * @param	string			$identifier	Identifier of this document.
	 * @param	mixed			$data		Document's data.
	 * @param	array			$meta		Document's metadata.
	 */
	public function __construct($collection, $identifier, $data, $meta) {
		$this->_collection = $collection;
		$this->_id = $identifier;
		$this->_data = $data;
		$this->_meta = $meta;
		$this->_modifiedMeta = array();
	}

	/* *********************** DOCUMENT MANAGEMENT METHODS ******************* */
	/**
	 * Returns the collection this document belongs to.
	 * @return	FineDBCollection	Document's collection.
	 */
	protected function _getCollection() {
		return ($this->_collection);
	}
	/**
	 * Returns the identifer of the current document.
	 * @return	string	Document's identifier.
	 */
	protected function _getId() {
		return ($this->_id);
	}
	/**
	 * Save the current document.
	 * @throws	ApplicationException	If this document was removed already.
	 * @throws	IOException		Data writing error.
	 */
	protected function _save() {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		if (!$this->_modified)
			return;
		$this->_collection->_updateDocument($this->_id, $this->_data, $this->_meta, $this->_modifiedMeta);
		$this->_modified = false;
		$this->_modifiedMeta = array();
	}
	/**
	 * Remove the current document.
	 * @throws	ApplicationException	If this document was removed already.
	 * @throws	IOException		Data writing error.
	 */
	protected function _remove() {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		$this->_collection->_removeDocument($this->_id);
		$this->_id = $this->_meta = $this->_data = $this->_collection = $this->_modifiedMeta = null;
	}

	/* *********************** METADATA MANAGEMENT METHODS ******************* */
	/**
	 * Returns the value of a metadata, or the full list of metadata.
	 * @param	string	$name	Metadata's name.
	 * @return	string	Metadata value.
	 * @throws	ApplicationException	If this document was removed already.
	 */
	protected function _getMeta($name=null) {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		if (!empty($name))
			return ($this->_meta[$name]);
		return ($this->_meta);
	}
	/**
	 * Modify a metadata.
	 * @param	string	$name	Metadata's name.
	 * @param	string	$value	Metadata's value.
	 * @throws	ApplicationException	If this document was removed already.
	 */
	protected function _setMeta($name, $value) {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		if ($value == $this->_meta[$name])
			return;
		$this->_modifiedMeta[$name] = $this->_meta[$name];
		$this->_meta[$name] = $value;
		$this->_modified = true;
	}

	/* *********************** DATA MANAGEMENT METHODS ******************* */
	/**
	 * Returns a document's datum.
	 * @param	string	$key	Name of the first-level data key.
	 * @return	mixed	Document's datum.
	 * @throws	ApplicationException	If this document was removed already.
	 */
	protected function _getDatum($key) {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		return (isset($this->_data[$key]) ? $this->_data[$key] : null);
	}
	/**
	 * Returns document's data.
	 * @return	mixed	Document's data.
	 * @throws	ApplicationException	If this document was removed already.
	 */
	protected function _getData() {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		return ($this->_data);
	}
	/**
	 * Modify a document's datum.
	 * @param	mixed	$key	The name of the first-level data key.
	 * @param	mixed	$data	(optional) The data to defined. Leave it null to remove the key.
	 * @throws	ApplicationException	If this document was already removed.
	 */
	protected function _setDatum($key, $data=null) {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		if (is_null($data))
			unset($this->_data[$key]);
		else
			$this->_data[$key] = $data;
		$this->_modified = true;
	}
	/**
	 * Modify document's data.
	 * @param	mixed	$data	The whole redefined data set.
	 * @throws	ApplicationException	If this document was removed already.
	 */
	protected function _setData($data) {
		if (is_null($this->_id))
			throw new ApplicationException("This document doesn't exists anymore.", ApplicationException::API);
		$this->_data = $data;
		$this->_modified = true;
	}
}

?>
